﻿//Copyright (C) 2009  Jaco & DarkXeD & Nader(ScionBot.com)

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Scion.Library.RS;
using System.Drawing;
using Scion.Core.Updater;

namespace Scion.Core
{
    /// <summary>
    /// Reflection hooks to get values from the RS client.
    /// </summary>
    public class Reflection
    {
        Stub stub;
        private static int[] CURVESIN = new int[2048];
        private static int[] CURVECOS = new int[2048];

        public Reflection(Stub s)
        {
            for (int i = 0; i < 2048; i++)
            {
                CURVESIN[i] = (int)(65536.0 * Math.Sin(i * 0.0030679615));
                CURVECOS[i] = (int)(65536.0 * Math.Cos(i * 0.0030679615));
            }
            stub = s;
        }

        /// <summary>
        /// The location of the character within the whole RS.
        /// </summary>
        /// <returns>Returns the tile the character is located at.</returns>
        public Tile GetCharacterTile()
        {
            try
            {
                Tile baseTile = GetBaseTile();
                Tile charTile = GetPlayerLocation();
                return new Tile(baseTile.x + charTile.x, baseTile.y + charTile.y);
            }
            catch
            {return new Tile(-1, -1);}
        }

        /// <summary>
        /// Gets the base tile of the character.
        /// </summary>
        /// <returns>Returns the base tile.</returns>
        public Tile GetBaseTile()
        {
            string result = stub.botBridge.SendInformation("GetIntStatic [" + Fields.BaseX + ";" + Fields.BaseY + "]");
            try
            {
                string[] Val = result.Trim().Split(' ');
                int x = int.Parse(Val[0].Trim());
                int y = int.Parse(Val[1].Trim());
                return new Tile(x, y);
            }
            catch
            {return new Tile(-1, -1);}
        }

        /// <summary>
        /// Gets the character location on the current ground.
        /// </summary>
        /// <returns>Returns the character location.</returns>
        public Tile GetPlayerLocation()
        {
            string result = stub.botBridge.SendInformation("GetIntArrayObject 0 (" + Fields.MyPlayer + ") [" + Fields.QueueX + ";" + Fields.QueueY + "]");
            try
            {
                string[] Val = result.Trim().Split(' ');
                int x = int.Parse(Val[0].Trim());
                int y = int.Parse(Val[1].Trim());
                return new Tile(x, y);
            }
            catch
            { return new Tile(-1, -1); }
        }

        /// <summary>
        /// Gets the current character location on the current ground.
        /// </summary>
        /// <returns>Returns the character location.</returns>
        public Tile GetPlayerLocation2()
        {
            string result = stub.botBridge.SendInformation("GetIntObject (" + Fields.MyPlayer + ") [" + Fields.CharX + ";" + Fields.CharY + "]");
            stub.botLog.WriteLine(result);
            try
            {
                string[] Val = result.Trim().Split(' ');
                int x = int.Parse(Val[0].Trim());
                int y = int.Parse(Val[1].Trim());
                return new Tile(x, y);
            }
            catch
            { return new Tile(-1, -1); }
        }

        /// <summary>
        /// Gets the Z-axis position of the camera.
        /// </summary>
        /// <returns>Returns the Z-axis of the camera.</returns>
        public int GetCameraPositionZ()
        {
            string result = stub.botBridge.SendInformation("GetIntStatic [" + Fields.CameraPositionZ + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1; }
        }

        /// <summary>
        /// Gets the angle of the compass.
        /// </summary>
        /// <returns>Returns the angle of the compass.</returns>
        public int GetCompassAngle()
        {
            string result = stub.botBridge.SendInformation("GetFloatStatic [" + Fields.CompassAngle + "]");
            try
            {return (int)float.Parse(result.Trim());}
            catch
            {return -1;}
        }

        /// <summary>
        /// Gets the map offset angle.
        /// </summary>
        /// <returns>Returns the map offset angle.</returns>
        public int GetMapOffsetAngle()
        {
            string result = stub.botBridge.SendInformation("GetIntStatic [" + Fields.MapOffsetAngle + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1; }
        }

        /// <summary>
        /// Gets the scale of the minimap.
        /// </summary>
        /// <returns>Returns the minimap scale.</returns>
        public int GetMinimapScale()
        {
            string result = stub.botBridge.SendInformation("GetIntStatic [" + Fields.MiniMapScale + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1; }
        }

        /// <summary>
        /// Gets the motion of the character.
        /// </summary>
        /// <returns>Returns the motion of the character.</returns>
        public int GetMotion()
        {
            string result = stub.botBridge.SendInformation("GetIntObject (" + Fields.MyPlayer + ") [" + Fields.Motion + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return 0; }
        }

        /// <summary>
        /// Gets the animation of the current character.
        /// </summary>
        /// <returns>Returns the animation of the current character.</returns>
        public int GetAnimation()
        {
            string result = stub.botBridge.SendInformation("GetIntObject (" + Fields.MyPlayer + ") [" + Fields.Animation + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1; }
        }

        /// <summary>
        /// Gets the loop cycle of RS.
        /// </summary>
        /// <returns>Returns the loop cycle.</returns>
        public int GetLoopCycle()
        {
            string result = stub.botBridge.SendInformation("GetIntStatic [" + Fields.LoopCycle + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1; }
        }

        /// <summary>
        /// Gets the loop status.
        /// </summary>
        /// <returns>Returns the loop status.</returns>
        public int GetLoopStatus()
        {
            string result = stub.botBridge.SendInformation("GetIntObject (" + Fields.MyPlayer + ") [" + Fields.LoopStatus + "]");
            try
            { return int.Parse(result.Trim()); }
            catch
            { return -1000; }
        }

        /// <summary>
        /// Figures out if the tile specified on the minimap is clickable.
        /// </summary>
        /// <param name="tile">The tile to test.</param>
        /// <returns>Returns true if the function succeeded.</returns>
        public bool PossibleMinimapClick(Tile tile)
        {
            int mmHeight = 140;
            int mmWidth = 140;
            double x = tile.x;
            double y = tile.y;
            Tile baseT = GetBaseTile();
            x -= baseT.x;
            y -= baseT.y;
            Tile playerT = GetPlayerLocation();
            int calculatedX = ((int)(x * 4 + 2)) - playerT.x * 4;
            int calculatedY = ((int)(y * 4 + 2)) - playerT.y * 4;
            int angle = GetCompassAngle() + GetMapOffsetAngle() & 0x7ff;
            int actDistSq = calculatedX * calculatedX + calculatedY * calculatedY;
            int mmDist = Math.Max(mmHeight / 2, mmWidth / 2);
            if (mmDist * mmDist >= actDistSq)
                return true;
            else return false;
        }


        /// <summary>
        /// Takes the tile and converts it to a clickable point on the minimap.
        /// </summary>
        /// <param name="tile">The tile to calculate.</param>
        /// <returns>Returns the converted coordinate.</returns>
        public Point ComputeMinimapTile(Tile tile)
        {
            int mmHeight = 152;
            int mmWidth = 152;
            int mmMasterX = 516;
            int mmMasterY = 0;
            int mmGetX = 35;
            int mmGetY = 9;
            double x = tile.x;
            double y = tile.y;
            Tile baseT = GetBaseTile();
            x -= baseT.x;
            y -= baseT.y;
            Tile playerT = GetPlayerLocation();
            int calculatedX = ((int)(x * 4 + 2)) - playerT.x * 4;
            int calculatedY = ((int)(y * 4 + 2)) - playerT.y * 4;
            int angle = GetCompassAngle() + GetMapOffsetAngle() & 0x7ff;
            int actDistSq = calculatedX * calculatedX + calculatedY * calculatedY;
            int mmDist = Math.Max(mmHeight / 2, mmWidth / 2);
            if (mmDist * mmDist >= actDistSq)
            {
                int cs = CURVESIN[angle];
                int fact = 256 + GetMinimapScale();
                cs = 256 * cs / fact;
                int cc = CURVECOS[angle];
                cc = 256 * cc / fact;
                int i_25_ = -(calculatedX * cs) + calculatedY * cc >> 16;
                int i_26_ = calculatedX * cc + calculatedY * cs >> 16;
                int screenx = (mmGetX + mmMasterX) + mmWidth / 2 + i_26_;
                int screeny = -i_25_ + mmHeight / 2 + (mmGetY + mmMasterY);
                return new Point(screenx, screeny);
            }
            else
            { return new Point(-1, -1);}
        }
    }
}
